<?php

namespace App\Services\ContractSign\Drivers;

use App\Services\ContractSign\ContractSignResult;
use App\Services\ContractSign\ContractSigner;
use com\junziqian\sdk\util\RequestUtils;
use Illuminate\Support\Facades\Log;
use RuntimeException;
use Throwable;

class JunziqianContractSigner implements ContractSigner
{
    protected array $config;

    public function __construct(array $config)
    {
        $this->config = $config;
    }

    public function applySign(array $params): ContractSignResult
    {
        $this->ensureConfigured();

        $applyPayload = $this->buildApplyPayload($params);

        Log::info('[ContractSign][Junziqian] applySign 请求参数', $applyPayload);

        try {
            $client = $this->createClient();
            $applyResponse = $client->doPost('/v2/sign/applySign', $applyPayload);
        } catch (Throwable $e) {
            Log::error('[ContractSign][Junziqian] applySign 请求异常', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);

            return ContractSignResult::failure('合同签署申请失败：' . $e->getMessage(), null, [
                'payload' => $applyPayload,
            ]);
        }

        $applyArray = $this->normalizeResponse($applyResponse);

        Log::info('[ContractSign][Junziqian] applySign 返回结果', $applyArray);

        if (($applyArray['success'] ?? false) !== true) {
            $message = (string) ($applyArray['msg'] ?? '申请失败');
            $code = (string) ($applyArray['code'] ?? '');

            return ContractSignResult::failure($message, $code ?: null, [
                'payload' => $applyPayload,
                'response' => $applyArray,
            ]);
        }

        $applyNo = $applyArray['data'] ?? null;
        if (! $applyNo) {
            return ContractSignResult::failure('合同签署申请未返回合同编号', null, [
                'payload' => $applyPayload,
                'response' => $applyArray,
            ]);
        }

        $linkPayload = $this->buildLinkPayload($params, $applyNo);

        Log::info('[ContractSign][Junziqian] link 请求参数', $linkPayload);

        try {
            $client = $this->createClient();
            $linkResponse = $client->doPost('/v2/sign/linkNew', $linkPayload);
        } catch (Throwable $e) {
            Log::error('[ContractSign][Junziqian] link 请求异常', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);

            return ContractSignResult::failure('合同签署链接获取失败：' . $e->getMessage(), null, [
                'apply' => $applyArray,
                'payload' => $linkPayload,
            ]);
        }

        $linkArray = $this->normalizeResponse($linkResponse);

        Log::info('[ContractSign][Junziqian] link 返回结果', $linkArray);

        if (($linkArray['success'] ?? false) !== true) {
            $message = (string) ($linkArray['msg'] ?? '获取签署链接失败');
            $code = (string) ($linkArray['code'] ?? '');

            return ContractSignResult::failure($message, $code ?: null, [
                'apply' => $applyArray,
                'payload' => $linkPayload,
                'response' => $linkArray,
            ]);
        }

        $linkData = $linkArray['data'] ?? [];

        return ContractSignResult::success([
            'applyNo' => $applyNo,
            'signUrl' => $linkData['shortUrl'] ?? '',
        ], $linkArray['message'] ?? '合同签署链接获取成功', [
            'apply' => $applyArray,
            'link' => $linkArray,
        ]);
    }

    public function fetchContractDocument(string $applyNo): ContractSignResult
    {
        $this->ensureConfigured();

        $endpoint = '/v2/sign/linkFile';
        $payload = ['applyNo' => $applyNo];

        Log::info('[ContractSign][Junziqian] fetchContractDocument 请求参数', [
            'endpoint' => $endpoint,
            'payload' => $payload,
        ]);

        try {
            $client = $this->createClient();
            $response = $client->doPost($endpoint, $payload);
        } catch (Throwable $e) {
            Log::error('[ContractSign][Junziqian] fetchContractDocument 请求异常', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);

            return ContractSignResult::failure('合同下载链接获取失败：' . $e->getMessage());
        }

        $responseArray = $this->normalizeResponse($response);

        Log::info('[ContractSign][Junziqian] fetchContractDocument 返回结果', $responseArray);

        if (($responseArray['success'] ?? false) !== true) {
            $message = (string) ($responseArray['msg'] ?? '合同下载链接获取失败');
            $code = (string) ($responseArray['resultCode'] ?? '');

            return ContractSignResult::failure($message, $code ?: null, [
                'payload' => $payload,
                'response' => $responseArray,
            ]);
        }

        $downloadUrl = $responseArray['data'] ?? null;
        if (! $downloadUrl) {
            return ContractSignResult::failure('合同下载链接不存在', null, [
                'payload' => $payload,
                'response' => $responseArray,
            ]);
        }

        return ContractSignResult::success([
            'downloadUrl' => $downloadUrl,
        ], $responseArray['msg'] ?? '合同下载链接获取成功', [
            'payload' => $payload,
            'response' => $responseArray,
        ]);
    }

    protected function ensureConfigured(): void
    {
        foreach (['service_url', 'app_key', 'app_secret'] as $key) {
            if (empty($this->config[$key])) {
                throw new RuntimeException(sprintf('合同签署 Junziqian 驱动缺少配置项 [%s]', $key));
            }
        }
    }

    protected function buildApplyPayload(array $params): array
    {
        return [
            'contractName' => $params['contractName'],
            'signatories'  => json_encode([
                [
                    'fullName'     => $params['fullNameLyp'],
                    'identityType' => 11,
                    'identityCard' => $params['identityCardLyp'],// ?? '91310104MAET1RJRXX',
                    'email'        => $params['emailLyp'],// ?? 'lyp@bccto.me',
                    'chapteName'   => $params['chapteNameLyp'],// ?? 'ebqLyp',
                    'signLevel'    => 1,
                    'signId'       => $params['signIdLyp'],
                    'serverCaAuto' => 1,
                ],
                [
                    'fullName'     => $params['fullName'],
                    'identityType' => $params['identityType'] ?? 1,
                    'identityCard' => $params['identityCard'],
                    'mobile'       => $params['mobile'],
                    'email'        => $params['email'] ?? 'shiverysea@gmail.com',
                    'authLevel'    => $params['authLevel'] ?? '[11]',
                    'chapteName'   => $params['chapteName'],
                    'signLevel'    => 1,
                    'noNeedVerify' => 1,
                ],
            ]),
            'serverCa'       => $params['serverCa'] ?? 0,   // 0为不需要
            'dealType'       => $params['dealType'] ?? 0,   // 为空或0时默认为手签合同(用户有感知);2只保全;5部份自动签;6HASH只保全;17收集信息批量签
            'templateNo'     => $params['templateNo'] ?? ($this->config['default_template_no'] ?? ''),
            'templateParams' => json_encode([
                'sohoName' => $params['fullName'],
                'idCard'   => $params['identityCard'],
                'merName'  => $params['tenantName'],
                'service'  => $params['taskName'],
                'mobile'   => $params['mobile'],
                'year'     => $params['year'],
                'month'    => $params['month'],
                'day'      => $params['day'],
            ]),
            'fileType'      => $params['fileType'] ?? 2,         // 2 API模版(HTML源码);4 API模板(PDF文件/word文件)
            'positionType'  => $params['positionType'] ?? 1,     // 指定公章位置类型:0或null使用签字座标位置或不指定签字位置;1表单域定位(表单域如果上传为pdf时,需pdf自行定义好表单域);2关键字定义
            'faceThreshold' => $params['faceThreshold'] ?? 75,
            'notifyUrl'     => $params['notifyUrl'] ?? ($this->config['notify_url'] ?? ''),
        ];
    }

    protected function buildLinkPayload(array $params, string $applyNo): array
    {
        return [
            'applyNo' => $applyNo,
            'fullName' => $params['fullName'] ?? '',
            'identityCard' => $params['identityCard'] ?? '',
            'identityType' => 1,
            'backUrl' => $params['backUrl'] ?? '',
        ];
    }

    protected function createClient(): RequestUtils
    {
        $serviceUrl = rtrim($this->config['service_url'], '/');
        $appKey = $this->config['app_key'];
        $appSecret = $this->config['app_secret'];
        $encryMethod = $this->config['encry_method'] ?? null;
        $tsType = $this->config['ts_type'] ?? 2;

        return new RequestUtils($serviceUrl, $appKey, $appSecret, $encryMethod, $tsType);
    }

    protected function normalizeResponse($response): array
    {
        if (is_array($response)) {
            return $response;
        }

        if (is_object($response)) {
            return json_decode(json_encode($response), true) ?: [];
        }

        return [];
    }
}
